// Author: Ivan Chau
package uk.ac.cam.kcic2.scene;

import java.util.ArrayList;

import uk.ac.cam.kcic2.math.Params;
import uk.ac.cam.kcic2.math.Polynomial;
import uk.ac.cam.kcic2.math.Transform;
import uk.ac.cam.kcic2.math.Vector3D;

public class Sphere extends Primitives {
	// in local coordinates, this is a unit sphere centred at origin
	private final double radius = 1;
	//public final double boundingRadius;

	public Sphere(ArrayList<Transform> worldTransform, ColourCoeffs coeffs, CompoundObject father){
		super(worldTransform, coeffs, father);
		//boundingRadius = localToWorldScaleTransform.maxScale();
	}

	@Override
	public IntersectionInfo getIntersection(Ray eye) {
		// transform the world ray to the sphere's local coordinates
		Vector3D localRayOrigin = worldToLocalPointTransform.mult(eye.origin);
		Vector3D localRayDirection = worldToLocalNormalTransform.mult(eye.direction);

		// Substitute the ray equation in the sphere vector equation
		double a = localRayDirection.dot(localRayDirection);
		double b = 2*localRayOrigin.dot(localRayDirection);
		double c = localRayOrigin.dot(localRayOrigin) - radius*radius;

		// Solve at^2 + bt + c = 0
		Polynomial subRayInSphere = new Polynomial(new double[]{c,b,a});
		// find the smallest t;
		double t = minT(subRayInSphere.getRoots());

		IntersectionInfo intersection = null;
		if (t < Double.POSITIVE_INFINITY && t > Params.EPILSON){
			// find the intersecting point and the unit surface normal in 
			// local coordinates
			Vector3D localIntersectPoint = localRayOrigin.plus(
					localRayDirection.mult(t));
			
			Vector3D localSurfaceNormal = localIntersectPoint;
			
			boolean inwards = true;
			if (localSurfaceNormal.dot(localRayDirection) > 0){	// check if the ray is coming from the inside
				localSurfaceNormal = localSurfaceNormal.mult(-1);
				inwards = false;
			}
			
			assert localSurfaceNormal.dot(localRayDirection) < 0;

			// transform these back to world coordinates
			Vector3D worldIntersectPoint = localToWorldPointTransform.mult(localIntersectPoint);
			Vector3D worldSurfaceNormal = localToWorldNormalTransform.mult(localSurfaceNormal).normalize();
			intersection = new IntersectionInfo(t, worldIntersectPoint,worldSurfaceNormal, this, inwards);
		}
		return intersection;
	}

}
